<?php

/*

    MMetaverse - Open Metaverse Access Library

    Copyright (c) 2009 Mary Jane Soft - Marlon J. Manrique

    http://www.maryjanesoft.com
    http://www.marlonj.com

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General
    Public License along with this library; if not, write to the
    Free Software Foundation, Inc., 59 Temple Place, Suite 330,
    Boston, MA  02111-1307  USA

    $Id$

*/

/**
 * @package mjs.mmetaverse.llsd
 */

/**
 * Parse a LLSD xml string to produce an array with the data 
 */
class MLLSDParser {

    /**
     * Array with the llsd information 
     *
     * @var array
     */
    private $data;

    /**
     * Current Key Value
     * 
     * @var string
     */
    private $currentKey;

    /**
     * Create a LLSD parser
     */
    private function MLLSDParser() {
        // Init array 
        $this->data = array();
    }

    /**
     * Parse the xml content like llsd 
     *
     * @param string $xml
     */
    private function parse($xml) {
        // Load the document inside a dom structure 
        $document = DOMDocument::loadXML($xml);

        // Get the root node
        $root = $document->documentElement;

        // Parse the data inside the node 
        $this->parseNode($root,$this->data);
    }

    /**
     * Parse a node information 
     *  
     * @param DOMNode $node next node to parse
     * @param array $parent parent of the node
     * @param boolean $isMap true if the structure is a map
     */
    private function parseNode($node, &$parent, $isMap = false) {
        // Get the first child
        // @var DOMNode
        $child = $node->firstChild;

        // Check the list of childs 
        while($child)
        {
            // Check the type of the element 
            if($child->nodeType == XML_ELEMENT_NODE) {
                // If map create an array to store the data 
                if($child->nodeName == 'map') {
                    // Create an array and parse the next node
                    // Add the childs like key=>value
                    $element = array();
                    $this->parseNode($child,$element,true);
                    // Add the map values to the parent
                    $parent[] = $element;
                }
                // If arra crate array to store the data 
                else if($child->nodeName == 'array') {
                    // Create an array and parse the next node
                    $element = array();

                    // Check if the array is inside a map
                    if($this->currentKey != NULL)
                        $keyName = $this->currentKey;

                    // Parse childs 
                    $this->parseNode($child,$element);

                    // Add the array values to the parent
                    if(isset($keyName)) {
                        $parent[$keyName] = $element;
                    }
                    else {
                        $parent[] = $element;
                    }
                }
                // If key read the name like the current key
                // To add in the mapping array 
                else if($child->nodeName == 'key') {
                    $this->currentKey = $child->textContent;
                }
                else {
                    // Get the value
                    $value = $child->textContent;

                    // Check if a map key is available 
                    if($this->currentKey != NULL) {
                        // Add the value from the map 
                        $parent[$this->currentKey] = $value;
                        // Reset the key value 
                        $this->currentKey = NULL;
                    }
                    else {
                        // Add the value to an array 
                        $parent[] = $value;
                    }
                }
            }

            // Next child 
            $child = $child->nextSibling;
        }
    }

    /**
     * Return the array with the representation of the llsd
     *
     * @return array
     */
    private function getData() {
        return $this->data;
    }

    /**
     * Parse the llsd content and return an array with the representation of the
     * values
     *
     * @param string $xml The llsd content
     * @return array The array representation of the llsd
     */
    public static function parseXML($xml) {
        // Create a parser
        $parser = new MLLSDParser();
        // Parse the xml
        $parser->parse($xml);
        // Return the array representation
        return $parser->getData();
    }
} 

?>